#include <avr/io.h>
#include "lcd.h"
#include <avr/pgmspace.h>

#define LCD_timing	4000
#define LCD_init_timingHigh	2000
#define LCD_init_itimingLow	200

static unsigned long data;
void Delay (unsigned long a) { while (--a!=0) asm("nop"); }

void E_Pulse()
{
  PORTG |= 1<<PG1; //set E to high
  Delay(20);
  PORTG &= ~(1<<PG1); //set E to low
}

void LCDInit()
{
  //first set D4, D5, D6, D7, LCD_LIGHT, RS, RW, E to output ports
  DDRC |= 0xff;
  DDRG |= (1<<PG0)|(1<<PG1);
  DDRA |= (1<<PA5);

  //LCD initialization
  //step by step from LCD Display data sheet
  PORTA &= ~(1<<PA5);  //set RS port to 0
  PORTG &= ~(1<<PG0);  //set R/W port to 0
  PORTG &= ~(1<<PG1);  //set E port to 0

   Delay(LCD_init_timingHigh);        //delay ~110ms

  PORTC |= (1<<PC4);   //set D4 port to 1
  PORTC |= (1<<PC5);   //set D5 port to 1
  E_Pulse();            //high->low to E port (pulse)
  Delay(LCD_init_itimingLow);         //delay ~10ms


  PORTC |= (1<<PC4);   //set D4 port to 1
  PORTC |= (1<<PC5);   //set D5 port to 1
  E_Pulse();           //high->low to E port (pulse)
  Delay(LCD_init_itimingLow);         //delay ~10ms


  PORTC |= (1<<PC4);   //set D4 port to 1
  PORTC |= (1<<PC5);   //set D5 port to 1
  E_Pulse();           //high->low to E port (pulse)
  Delay(LCD_init_itimingLow);         //delay ~10ms

  PORTC |= (1<<PC5);   //set D5 port to 1
  PORTC &= ~(1<<PC4);  //set D4 port to 0
  E_Pulse();           //high->low to E port (pulse)
  Delay(LCD_init_itimingLow);         //delay ~10ms

  LCDSendCommand(DISP_ON);      //LCD on
  LCDSendCommand(0x28);			//two row
  LCDSendCommand(CLR_DISP);     //LCD clear
  LCDSendCommand(DD_RAM_ADDR+2);  //LCD set first row 
}

void LCDSendCommand(unsigned long a)
{

  PORTG &= ~(1<<PG0);                    //set RW port to 0

  Delay(LCD_timing);                          //delay for LCD char ~2ms

  data = (0xf0 & a);                //get high 4 bits
  PORTC &= ~(0xf0);                      //clear D4-D7
  PORTC |= data;                         //set D4-D7
  PORTA &= ~(1<<PA5);                    //set RS port to 0 -> display set to comand mode
  E_Pulse();                             //pulse to set d4-d7 bits


  data = a & 0x0f;   	                 //get low 4 bits
  PORTC &= ~(0xf0);                      //clear D4-D7
  PORTC |= data<<4;	                     //set D4-D7 (only PORTC4-PORTC7)
  PORTA &= ~(1<<PA5);                    //set RS port to 0 -> display set to command mode
  E_Pulse(); 
}

void LCDSendChar(unsigned long a)
{                       
 
  PORTG &= ~(1<<PG0);                    //set RW port to 0

  Delay(LCD_timing);                          //delay for LCD char ~2ms

  data = (0xf0 & a);                //get high 4 bits
  PORTC &= ~(0xf0);                      //clear D4-D7
  PORTC |= data;                         //set D4-D7
  PORTA |= (1<<PA5);                    //set RS port to 0 -> display set to comand mode
  E_Pulse();                             //pulse to set d4-d7 bits


  data = a & 0x0f;   	                 //get low 4 bits
  PORTC &= ~(0xf0);                      //clear D4-D7
  PORTC |= data<<4;	                     //set D4-D7 (only PORTC4-PORTC7)
  PORTA |= (1<<PA5);                    //set RS port to 0 -> display set to command mode
  E_Pulse();                                              //pulse to set d4-d7 bit                          
}


void LDCsendStr (unsigned char *byte)
{
  unsigned char *LDCbuffer;
  LDCbuffer = byte;
  do{
    LCDSendChar(*LDCbuffer);
    LDCbuffer++;
    }while(*LDCbuffer != 0x00);
}

void LDCsendStr_FLASH (unsigned char *byte)
{
  unsigned char *LDCbuffer;
  LDCbuffer = byte;
  do{
    LCDSendChar(pgm_read_byte(LDCbuffer));
    LDCbuffer++;
    }while(pgm_read_byte(LDCbuffer) != 0x00);
}

void LCD_show_numb (unsigned short *LDCbuffer,unsigned point_position)
{
unsigned char d1000;
unsigned char d100;
unsigned char d10;
unsigned char d1;

 d1000 = (unsigned char)(*LDCbuffer / 1000);
 d100 = (unsigned char)((*LDCbuffer%1000) / 100);
 d10 = (unsigned char)((*LDCbuffer%100) / 10);
 d1 = (unsigned char)(*LDCbuffer % 10);

 if (point_position == 1) 
 {
	 LCDSendChar(d1000 + '0');
	 LCDSendChar('.');
	 LCDSendChar(d100 + '0');
	 LCDSendChar(d10 + '0');
	 LCDSendChar(d1 + '0');
 }
 else if (point_position == 2) 
 {
  	 LCDSendChar(d1000 + '0');	 
	 LCDSendChar(d100 + '0');
	 LCDSendChar('.');
	 LCDSendChar(d10 + '0');
	 LCDSendChar(d1 + '0');
 }
 else if (point_position == 3) 
 {
  	 LCDSendChar(d1000 + '0');	 
	 LCDSendChar(d100 + '0'); 
	 LCDSendChar(d10 + '0');
	 LCDSendChar('.');
	 LCDSendChar(d1 + '0');
 }
 else if (point_position == 255) 
 {
  	 LCDSendChar(d1000 + '0');	 
	 LCDSendChar(d100 + '0');
	 LCDSendChar(d10 + '0');
	 LCDSendChar(d1 + '0');
 }
}

void runningString (void)
{
  LCDSendCommand(0x18);
  Delay (650000);
}
